
use proto::{new_frame, new_min_frame, new_res_frame};
use tokio::{io::AsyncWriteExt, net::tcp::OwnedWriteHalf, sync::Mutex};

use crate::{AppErr};

#[derive(Debug)]
struct Inner {
    tx: OwnedWriteHalf,
    close_flag: bool,
}

#[derive(Debug)]
pub struct ConnWriter {
    inner: Mutex<Inner>,
}

impl ConnWriter {
    pub fn new(tx: OwnedWriteHalf) -> ConnWriter {
        ConnWriter {
            inner: Mutex::new(Inner {
                tx,
                close_flag: false,
            }),
        }
    }

    pub async fn close(&self) {
        let mut w = self.inner.lock().await;
        w.close_flag = true;
    }

    pub async fn write(&self, buf: &[u8]) -> Result<(), AppErr> {
        let mut w = self.inner.lock().await;
        if w.close_flag {
            return Err(AppErr::Closed("已经断开"));
        }
        w.tx.write_all(buf).await?;
        Ok(())
    }

    pub async fn write_min_frame(&self, ts: u8, seq: u8) -> Result<(), AppErr> {
        self.write(&new_min_frame(ts, seq)).await
    }

    pub async fn write_frame(&self, ts: u8, seq: u8, cmd: u16, body: &[u8]) -> Result<(), AppErr> {
        self.write(&new_frame(ts, seq, cmd, body)).await
    }

    pub async fn write_res_frame(
        &self,
        ts: u8,
        seq: u8,
        cmd: u16,
        state: u8,
        body: &[u8],
    ) -> Result<(), AppErr> {
        self.write(&new_res_frame(ts, seq, cmd, state, body)).await
    }
}
